
package com.dingmouren.layoutmanagergroup.echelon;

import com.ohos.RecyclerContainer;

import ohos.agp.components.Component;
import ohos.app.Context;

import java.util.ArrayList;

/**
 * Created by 钉某人
 * github: https://github.com/DingMouRen
 * email: naildingmouren@gmail.com
 */

public class EchelonLayoutManager extends RecyclerContainer.LayoutManager {
    private static final String TAG = "EchelonLayoutManager";
    private Context mContext;
    private int mItemViewWidth;
    private int mItemViewHeight;
    private int mItemCount;
    private int mScrollOffset = Integer.MAX_VALUE;
    private float mScale = 0.9f;

    /**
     * EchelonLayoutManager Constructor
     */
    public EchelonLayoutManager(Context context) {
        this.mContext = context;
    }

    @Override
    public RecyclerContainer.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerContainer.LayoutParams(RecyclerContainer.LayoutParams.MATCH_CONTENT,
                RecyclerContainer.LayoutParams.MATCH_CONTENT);
    }

    @Override
    public void layoutChildren(RecyclerContainer.Adapter adapter, RecyclerContainer.Recycler recycler) {
        mItemViewWidth = (int) (getHorizontalSpace() * 0.87f);
        mItemViewHeight = (int) (mItemViewWidth * 1.46f);
        recycler.scrapAllViewsAttached();
        mItemCount = getRecyclerView().getAdapter().getItemCount();
        mScrollOffset = Math.min(Math.max(mItemViewHeight, mScrollOffset), mItemCount * mItemViewHeight);
        layoutChild(recycler);
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerContainer.Adapter adapter, RecyclerContainer.Recycler recycler) {
        int pendingScrollOffset = mScrollOffset + dy;
        mScrollOffset = Math.min(Math.max(mItemViewHeight, mScrollOffset + dy), mItemCount * mItemViewHeight);
        layoutChild(recycler);
        return mScrollOffset - pendingScrollOffset + dy;
    }

    @Override
    public boolean canScrollVertically() {
        return true;
    }

    private void layoutChild(RecyclerContainer.Recycler recycler) {
        if (getRecyclerView().getAdapter().getItemCount() == 0) {
            return;
        }
        int bottomItemPosition = (int) Math.floor(mScrollOffset / mItemViewHeight);
        int remainSpace = getVerticalSpace() - mItemViewHeight;
        int bottomItemVisibleHeight = mScrollOffset % mItemViewHeight;
        final float offsetPercentRelativeToItemView = bottomItemVisibleHeight * 1.0f / mItemViewHeight;
        ArrayList<ItemViewInfo> layoutInfos = new ArrayList<>();
        for (int i = bottomItemPosition - 1, j = 1; i >= 0; i--, j++) {
            double maxOffset = (getVerticalSpace() - mItemViewHeight) / 2 * Math.pow(0.8, j);
            int start = (int) (remainSpace - offsetPercentRelativeToItemView * maxOffset);
            float scaleXY = (float) (Math.pow(mScale, j - 1) * (1 - offsetPercentRelativeToItemView * (1 - mScale)));
            float layoutPercent = start * 1.0f / getVerticalSpace();
            ItemViewInfo info = new ItemViewInfo(start, scaleXY, offsetPercentRelativeToItemView,
                    layoutPercent);
            layoutInfos.add(0, info);
            remainSpace = (int) (remainSpace - maxOffset);
            if (remainSpace <= 0) {
                info.setTop((int) (remainSpace + maxOffset));
                info.setPositionOffset(0);
                info.setLayoutPercent(info.getTop() / getVerticalSpace());
                info.setScaleXY((float) Math.pow(mScale, j - 1));
                break;
            }
        }
        if (bottomItemPosition < mItemCount) {
            final int start = getVerticalSpace() - bottomItemVisibleHeight;
            layoutInfos.add(new ItemViewInfo(start, 1.0f,
                    bottomItemVisibleHeight * 1.0f / mItemViewHeight,
                    start * 1.0f / getVerticalSpace()).setIsBottom());
        } else {
            bottomItemPosition = bottomItemPosition - 1;
        }
        int layoutCount = layoutInfos.size();
        final int startPos = bottomItemPosition - (layoutCount - 1);
        final int endPos = bottomItemPosition;
        final int childCount = getRecyclerView().getChildCount();
        for (int ival = childCount - 1; ival >= 0; ival--) {
            RecyclerContainer.ViewHolder viewHolder = getRecyclerView().findViewHolderForPosition(ival);
            Component childView = getRecyclerView().getChildAt(ival);
            if (viewHolder != null) {
                int pos = 0;
                if (childView.getTag() instanceof RecyclerContainer.ViewHolder) {
                    pos = ((RecyclerContainer.ViewHolder) childView.getTag()).getPosition();
                }
                if (pos > endPos || pos < startPos) {
                    recycler.detachAndScrapView(childView);
                }
            }
        }
        recycler.detachDirtyScrapViews();
        for (int ival = 0; ival < layoutCount; ival++) {
            Component view = recycler.getViewForPosition(startPos + ival);
            ItemViewInfo layoutInfo = layoutInfos.get(ival);
            addView(view);
            measureChildWithExactlySize(view);
            int left = (getHorizontalSpace() - mItemViewWidth) / 2;
            getRecyclerView().layoutDecoratedWithMargins(view, left,
                    layoutInfo.getTop(), left + mItemViewWidth, layoutInfo.getTop()
                            + mItemViewHeight);
            view.setWidth(mItemViewWidth);
            view.setPivotX(view.getWidth() / 2);
            view.setPivotY(0);
            view.setScaleX(layoutInfo.getScaleXY());
            view.setScaleY(layoutInfo.getScaleXY());
        }
    }

    private void measureChildWithExactlySize(Component child) {
        final int widthSpec =
                Component.MeasureSpec.getMeasureSpec(mItemViewWidth, Component.MeasureSpec.PRECISE);
        final int heightSpec =
                Component.MeasureSpec.getMeasureSpec(mItemViewHeight, Component.MeasureSpec.PRECISE);
        child.setWidth(widthSpec);
        child.setWidth(heightSpec);
    }

    private int getVerticalSpace() {
        return getRecyclerView().getHeight() - getRecyclerView().getPaddingTop()
                - getRecyclerView().getPaddingBottom();
    }

    private int getHorizontalSpace() {
        return getRecyclerView().getWidth() - getRecyclerView().getPaddingLeft()
                - getRecyclerView().getPaddingRight();
    }
}
